home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
QRZ! Ham Radio 11
/
QRZ Ham Radio Callsign Database - Volume 11.iso
/
files
/
packet
/
ax25ip.shr
/
tty_ax.c
< prev
Wrap
C/C++ Source or Header
|
1998-02-02
|
24KB
|
1,087 lines
/*
* KISS+AX25 IP streams module for sunos 4.x
*
* Copyright 1991, 1992 by Theo de Raadt
*
* Theo de Raadt <deraadt@lego.cuc.ab.ca>
* Thanks to William Graham <uug@indigo.cuc.ab.ca> for AX25 specs.
*
* Streams ideas ripped off from PPP and SLIP implimentations for
* Sunos by Brad Clements and Rayan Zachariassen respectively.
*/
#undef DEBUG
#undef DEBUG2
#define AX_NIT
#include "ax.h"
#if NAX > 0
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stream.h>
#include <sys/stropts.h>
#include <sys/dir.h>
#include <sys/signal.h>
#include <sys/user.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/syslog.h>
#include <netinet/in.h>
#include <net/if.h>
#include <net/nit_if.h>
#include <netinet/if_ether.h>
#include <sys/if_ax.h>
#include <net/netisr.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
#ifdef AX_NIT
static struct ether_header nitheader = { {{1}}, {{2}}, ETHERTYPE_IP };
static struct nit_if nif = {(caddr_t)&nitheader, sizeof(nitheader), 0, 0};
static struct ether_header nitheader_arp = { {{1}}, {{2}}, ETHERTYPE_ARP };
static struct nit_if nif_arp = {(caddr_t)&nitheader_arp, sizeof(nitheader_arp), 0, 0};
#endif
int ax_attach();
static int ax_open(), ax_close(), ax_rput(), ax_wput(), ax_wsrv();
static int ax_ioctl(), ax_output();
static struct mbuf *ax_btom();
static struct module_info minfo = {
0xabce, AXSTREAMNAME, 0, INFPSZ, 16384, 4096
};
static struct qinit r_init = {
ax_rput, NULL, ax_open, ax_close, NULL, &minfo, NULL
};
static struct qinit w_init = {
ax_wput, ax_wsrv, ax_open, ax_close, NULL, &minfo, NULL
};
struct streamtab axinfo = {
&r_init, &w_init, NULL, NULL, NULL
};
static struct axpriv {
struct arpcom arpcom;
queue_t *q;
u_char *buf;
u_char *dp;
u_int inlen;
u_char gotesc, toobig;
} axpriv[NAX];
static u_char ax25broadcastaddr[7] = {
'Q'<<1, 'S'<<1, 'T'<<1, ' '<<1, ' '<<1, ' '<<1, '0'<<1
};
static struct ether_addr ethernulladdr;
int
ax_attach(unit)
int unit;
{
register struct ifnet *ifp = &axpriv[unit].arpcom.ac_if;
ifp->if_name = AXIFNAME;
ifp->if_mtu = AX25MTU;
ifp->if_flags = IFF_BROADCAST;
ifp->if_unit = unit;
ifp->if_ioctl = ax_ioctl;
ifp->if_output = ax_output;
ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
if_attach(ifp);
return 0;
}
static int
ax_open(q, dev, flag, sflag)
queue_t *q;
dev_t dev;
int flag, sflag;
{
struct axpriv *axp;
int unit, s;
if( !suser()) {
u.u_error = EPERM;
return OPENFAIL;
}
s = splstr();
for( unit=0; unit<NAX; ++unit) {
axp = &axpriv[unit];
if(axp->buf)
continue;
if(axp->arpcom.ac_if.if_mtu == 0)
ax_attach(unit);
axp->arpcom.ac_if.if_flags |= IFF_RUNNING;
axp->buf = (u_char *)kmem_alloc(AX25MTU);
axp->dp = axp->buf + sizeof(struct ifnet *);
axp->inlen = 0;
axp->q = WR(q);
WR(q)->q_ptr = q->q_ptr = (caddr_t)axp;
(void) splx(s);
log(LOG_INFO, "ax%d: coming up\n", unit);
return unit;
}
splx(s);
log(LOG_INFO, "ax%d: no more devices available\n", NAX);
return OPENFAIL;
}
static int
ax_close(q, flag)
queue_t *q;
int flag;
{
struct axpriv *axp;
int s;
s = splimp();
axp = (struct axpriv *)q->q_ptr;
if(axp) {
log(LOG_INFO, "ax%d: going down\n", axp->arpcom.ac_if.if_unit);
if_down(&axp->arpcom.ac_if);
axp->arpcom.ac_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
if(axp->buf)
kmem_free(axp->buf, AX25MTU);
axp->buf = NULL;
axp->q = NULL;
}
(void) splx(s);
}
static int
ax_wput(q, mp)
queue_t *q;
mblk_t *mp;
{
struct axpriv *axp;
char ax25[7];
struct iocblk *iocp;
switch(mp->b_datap->db_type) {
case M_FLUSH:
if(*mp->b_rptr & FLUSHW)
flushq(q, FLUSHDATA);
putnext(q, mp);
break;
case M_DATA:
putq(q, mp);
break;
case M_IOCTL:
iocp = (struct iocblk *)mp->b_rptr;
axp = (struct axpriv *)q->q_ptr;
switch(iocp->ioc_cmd) {
case AXIOSHADDR:
bcopy((caddr_t)mp->b_cont->b_rptr,
(caddr_t)&axp->arpcom.ac_enaddr,
sizeof(struct ether_addr));
mp->b_datap->db_type = M_IOCACK;
iocp->ioc_rval = iocp->ioc_count = iocp->ioc_error = 0;
qreply(q, mp);
log(LOG_INFO, "ax%d: ether %2x:%2x:%2x:%2x:%2x:%2x ax25 ",
axp->arpcom.ac_if.if_unit,
axp->arpcom.ac_enaddr.ether_addr_octet[0],
axp->arpcom.ac_enaddr.ether_addr_octet[1],
axp->arpcom.ac_enaddr.ether_addr_octet[2],
axp->arpcom.ac_enaddr.ether_addr_octet[3],
axp->arpcom.ac_enaddr.ether_addr_octet[4],
axp->arpcom.ac_enaddr.ether_addr_octet[5]);
ax_ether2ax(&axp->arpcom.ac_enaddr, ax25);
print_ax25addr(ax25);
printf("\n");
return;
case AXIOGUNIT:
iocp->ioc_rval = 0;
if( mp->b_cont = allocb(sizeof(int), BPRI_MED) ) {
u_char *cp = mp->b_cont->b_wptr;
mp->b_datap->db_type = M_IOCACK;
*((int *)cp) = axp->arpcom.ac_if.if_unit;
mp->b_cont->b_wptr += sizeof(int);
iocp->ioc_count = sizeof(int);
iocp->ioc_error = 0;
qreply(q, mp);
break;
}
iocp->ioc_error = ENOSR;
mp->b_datap->db_type = M_IOCNAK;
qreply(q, mp);
return;
default:
log(LOG_INFO, "ax%d: unknown ioc %8x\n",
axp->arpcom.ac_if.if_unit, iocp->ioc_cmd);
putnext(q, mp);
return;
}
break;
default:
putnext(q, mp);
}
}
static int
ax_rput(q, mp)
queue_t *q;
mblk_t *mp;
{
struct axpriv *axp = (struct axpriv *)q->q_ptr;
struct ifnet *ifp;
register u_char c, *rp;
register mblk_t *bp;
struct mbuf *m;
int proto, forus, s;
if( axp==NULL ) {
log(LOG_INFO, "ax_rput: axp is NULL\n");
freemsg(mp);
return;
}
if( axp->buf==NULL ) {
log(LOG_INFO, "ax_rput: axp->buf is NULL\n");
freemsg(mp);
return;
}
ifp = &axp->arpcom.ac_if;
switch(mp->b_datap->db_type) {
case M_DATA:
break;
case M_FLUSH:
if(*mp->b_rptr & FLUSHR)
flushq(q, FLUSHDATA);
putnext(q, mp);
return;
case M_UNHANGUP:
log(LOG_INFO, "ax%d: M_UNHANGUP\n", ifp->if_unit);
axp->q = WR(q); /* hook us up again */
putnext(q, mp);
putctl1(q->q_next, M_PCSIG, SIGURG);
return;
case M_HANGUP:
log(LOG_INFO, "ax%d: M_HANGUP\n", ifp->if_unit);
s = splstr();
axp->q = NULL; /* cause ax_output to return ENETDOWN */
(void) splx(s);
putnext(q, mp);
return;
case M_BREAK:
case M_IOCACK:
putnext(q, mp);
return;
default:
log(LOG_INFO, "ax%d: rput streams message type %d discarded\n",
ifp->if_unit, mp->b_datap->db_type);
putnext(q, mp);
return;
}
/*
* Perform the KISS protocol on the streams message, and add the bytes
* to a packet reconstruction buffer. When a complete AX25 packet has
* been collected, strip the AX25 layer and provide the IP (or ARP) packet
* inside to the networking code.
*/
for( bp=mp; bp; bp=bp->b_cont) {
rp = bp->b_rptr;
while( rp < bp->b_wptr) {
c = *rp++;
/*printf("K %2x\n", c);*/
if(axp->gotesc) {
axp->gotesc = 0;
if(c==KISS_TEND)
c = KISS_END;
else if(c==KISS_TESC)
c = KISS_ESC;
#ifdef DEBUG
else
log(LOG_INFO, "ax%d: kiss ESC error (c=%d)\n",
ifp->if_unit, c);
#endif
} else if(c==KISS_END) {
if(axp->toobig) {
axp->toobig = 0;
/*printf("ax%d: packet toobig\n",
ifp->if_unit);*/
axp->inlen = 0;
continue;
}
if(axp->inlen==0)
continue;
/*
* buf contains KISS_DATA followed by an AX25
* packet. Extract the IP packet lurking inside
* AX25 packet..
*/
m = ax_btom(axp, &proto, &forus);
axp->dp = axp->buf + sizeof(struct ifnet *);
ifp->if_ipackets++;
axp->inlen = 0;
if(!m) {
ifp->if_ierrors++;
continue;
}
switch(proto) {
case AX25PID_IP:
#ifdef AX_NIT
if(ifp->if_flags & IFF_PROMISC) {
struct mbuf *nm = m;
int len = 0;
do {
len += nm->m_len;
} while( nm=nm->m_next );
len -= sizeof(struct ifnet *);
m->m_off += sizeof(struct ifnet *);
nif.nif_bodylen = len;
snit_intr(&axp->arpcom, m, &nif);
m->m_off -= sizeof(struct ifnet *);
}
#endif
if(!forus) {
m_freem(m);
break;
}
s = splimp();
if( IF_QFULL(&ipintrq) ) {
IF_DROP(&ipintrq);
ifp->if_ierrors++;
m_freem(m);
(void) splx(s);
} else {
IF_ENQUEUE(&ipintrq, m);
schednetisr(NETISR_IP);
(void) splx(s);
#ifdef DEBUG
log(LOG_INFO, "handing off to IP\n");
#endif
}
break;
case AX25PID_ARP:
#ifdef AX_NIT
if(ifp->if_flags & IFF_PROMISC) {
struct mbuf *nm = m;
int len = 0;
do {
len += nm->m_len;
} while( nm=nm->m_next );
len -= sizeof(struct ifnet *);
m->m_off += sizeof(struct ifnet *);
nif_arp.nif_bodylen = len;
snit_intr(&axp->arpcom, m, &nif_arp);
m->m_off -= sizeof(struct ifnet *);
}
#endif
if(!forus) {
m_freem(m);
break;
}
#ifdef DEBUG
printf("[INCOMING ethernet arp packet]");
ax25_arpdebug(m);
#endif
arpinput(&axp->arpcom, m);
break;
default:
#ifdef DEBUG2
printf("ax%d: unknown protocol %d\n",
ifp->if_unit,
proto);
#endif
m_freem(m);
break;
}
continue;
} else if(c==KISS_ESC) {
axp->gotesc = 1;
continue;
}
if(++axp->inlen > AX25MTU) {
if(axp->toobig)
continue;
axp->toobig = 1;
ifp->if_ierrors++;
axp->dp = axp->buf + sizeof(struct ifnet *);
continue;
} else
*axp->dp++ = c;
}
bp->b_rptr = rp;
}
freemsg(mp);
return;
}
static struct mbuf *
ax_btom(axp, protop, forusp)
struct axpriv *axp;
int *protop, *forusp;
{
struct ax25_hdr *ax;
struct mbuf *m, **mp, *top = NULL;
struct ifnet *ifp;
struct ether_addr oureth;
int len, count;
caddr_t cp;
ax = (struct ax25_hdr *)(axp->buf + sizeof(struct ifnet *) + 1);
/*
* digipeaters are not supported (they could be supported - could
* correct the AX25 packet's fields, KISS encode it, and send a
* message downstream to the TNC.)
*
* The IP packet must come in an AX25 UI frame.
*/
if(ax->ah_cmd != AX25CMD_UI) {
#ifdef DEBUG2
printf("ax%d: ax25 frame not UI, cmd=%2x\n",
axp->arpcom.ac_if.if_unit, ax->ah_cmd);
#endif
return NULL;
}
#ifdef DEBUG2
printf("ax%d: ", axp->arpcom.ac_if.if_unit);
print_ax25addr(ax->ah_src);
printf("->");
print_ax25addr(ax->ah_dst);
printf(" [%d]\n", axp->inlen - sizeof(struct ax25_hdr) - 1);
#endif
/*
* is this packet to us?
*/
*forusp = 1;
ax_ax2ether(ax->ah_dst, &oureth);
if( bcmp((caddr_t)&oureth, (caddr_t)&axp->arpcom.ac_enaddr,
sizeof oureth) &&
bcmp((caddr_t)ax25broadcastaddr, (caddr_t)&axp->arpcom.ac_enaddr,
sizeof oureth)) {
*forusp = 0;
}
/*
* packet not for us, and not promisc mode --> can out.
*/
if( !(axp->arpcom.ac_if.if_flags & IFF_PROMISC) && *forusp==0)
return NULL;
/*
* check acceptable protocols
*/
switch(ax->ah_pid) {
case AX25PID_IP:
case AX25PID_ARP:
break;
default:
#ifdef DEBUG2
printf("ax%d: packet discarded - protocol %d\n",
axp->arpcom.ac_if.if_unit, ax->ah_pid);
#endif
return NULL;
}
*protop = (int)(ax->ah_pid);
ifp = &axp->arpcom.ac_if;
cp = (caddr_t)(axp->buf + sizeof(struct ifnet *) + 1 + sizeof(struct ax25_hdr));
mp = ⊤
len = axp->inlen - 1 - sizeof(struct ax25_hdr);
while(len>0) {
MGET(m, M_DONTWAIT, MT_DATA);
if(m == NULL) {
if(top)
m_freem(top);
return NULL;
}
*mp = m;
if(ifp) {
m->m_off += sizeof(ifp);
count = MIN(len, MLEN - sizeof(ifp));
bcopy(cp, mtod(m, caddr_t), count);
m->m_len = count;
m->m_off -= sizeof(ifp);
m->m_len += sizeof(ifp);
*mtod(m, struct ifnet **) = ifp;
ifp = NULL;
} else {
count = MIN(len, MLEN);
bcopy(cp, mtod(m, caddr_t), count);
m->m_len = count;
}
cp += count;
len -= count;
mp = &m->m_next;
}
if(ax->ah_pid== AX25PID_ARP) {
top->m_off += sizeof(ifp); /* XXX ax_ax2etherarp() weak */
ax_ax2etherarp(top);
top->m_off -= sizeof(ifp);
}
return top;
}
static int
ax_wsrv(q)
queue_t *q;
{
register mblk_t *mp;
while( mp=getq(q) ) {
if( !canput(q->q_next)) {
putbq(q, mp);
return;
}
putnext(q, mp);
}
}
/* %%% ifconfig ether #:#:#:#:#:# not working */
static int
ax_ioctl(ifp, cmd, data)
struct ifnet *ifp;
int cmd;
caddr_t data;
{
register struct ifaddr *ifa = (struct ifaddr *)data;
register struct ifreq *ifr = (struct ifreq *)data;
int error = 0, s;
if(ifa==NULL)
return EFAULT;
s = splimp();
switch(cmd) {
case SIOCSIFFLAGS:
if(!data) /* IFF_PROMISC change */
break;
if(!suser()) {
error = EPERM;
break;
}
ifp->if_flags &= IFF_CANTCHANGE;
ifp->if_flags |= (ifr->ifr_flags & ~IFF_CANTCHANGE);
break;
case SIOCGIFFLAGS:
ifr->ifr_flags = ifp->if_flags;
break;
case SIOCSIFADDR:
switch(ifa->ifa_addr.sa_family) {
case AF_INET:
((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr;
ifp->if_flags |= IFF_UP;
break;
default:
error = EAFNOSUPPORT;
break;
}
break;
case SIOCSIFBRDADDR:
if(ifa->ifa_addr.sa_family != AF_INET)
error = EAFNOSUPPORT;
break;
case SIOCSIFNETMASK:
if(ifa->ifa_addr.sa_family != AF_INET)
error = EAFNOSUPPORT;
break;
default:
error = EINVAL;
}
(void) splx(s);
return error;
}
static int
ax_output(ifp, m0, dst)
struct ifnet *ifp;
struct mbuf *m0;
struct sockaddr *dst;
{
struct axpriv *axp;
struct ax25_hdr ax25;
struct ether_header *eth;
struct mbuf *m = m0;
int i, len, s, n;
struct in_addr idst;
u_char *cp, *cp2;
mblk_t *mp;
axp = &axpriv[ifp->if_unit];
if(axp->q == NULL)
return ENETDOWN;
/* printf("ax%d: trying to send packet\n", ifp->if_unit); */
switch(dst->sa_family) {
case AF_INET:
#ifdef AX_NIT
if(axp->arpcom.ac_if.if_flags & IFF_PROMISC) {
struct mbuf *nm = m0;
int len = 0;
do {
len += nm->m_len;
} while( nm=nm->m_next );
nif.nif_bodylen = len;
snit_intr(&axp->arpcom, m0, &nif);
}
#endif
idst = ((struct sockaddr_in *)dst)->sin_addr;
((struct arpcom *)ifp)->ac_lastip = idst;
m = m0;
if( !arpresolve((struct arpcom *)ifp, m)) {
return 0;
}
#ifdef DEBUG2
len = 0;
for(m=m0; m; m=m->m_next) {
cp = mtod(m, u_char *);
n = m->m_len;
while(n-->0) {
if( !(len++ % 16) )
printf("\n\t");
printf("%2x ", *cp++);
}
}
if( len % 16 )
printf("\n");
#endif
ax25.ah_pid = AX25PID_IP;
ax_ether2ax(&((struct arpcom *)ifp)->ac_enaddr, ax25.ah_src);
ax_ether2ax(&((struct arpcom *)ifp)->ac_lastarp, ax25.ah_dst);
#ifdef DEBUG2
printf("ax%d: sending to ", ifp->if_unit);
print_ax25addr(ax25.ah_dst);
printf("\n");
#endif
break;
case AF_UNSPEC:
eth = (struct ether_header *)dst->sa_data;
switch(eth->ether_type) {
case ETHERTYPE_ARP:
case ETHERTYPE_REVARP:
#ifdef AX_NIT
if(axp->arpcom.ac_if.if_flags & IFF_PROMISC) {
struct mbuf *nm = m0;
int len = 0;
do {
len += nm->m_len;
} while( nm=nm->m_next );
nif_arp.nif_bodylen = len;
snit_intr(&axp->arpcom, m0, &nif_arp);
}
#endif
#ifdef DEBUG2
printf("AF_UNSPEC: ARP\n");
printf("[ethernet arp packet]");
len = 0;
for(m=m0; m; m=m->m_next) {
cp = mtod(m, u_char *);
n = m->m_len;
while(n-->0) {
if( !(len++ % 16) )
printf("\n\t");
printf("%2x ", *cp++);
}
}
if( len % 16 )
printf("\n");
#endif
ax_ether2axarp(m0);
ax25.ah_pid = AX25PID_ARP;
ax_ether2ax(&((struct arpcom *)ifp)->ac_enaddr, ax25.ah_src);
ax_ether2ax(ð->ether_dhost, ax25.ah_dst);
#ifdef DEBUG2
printf("[AX25 arp packet]");
#endif
break;
default:
printf("AF_UNSPEC: unknown ether_type %4x",
ntohs(eth->ether_type));
ax25.ah_pid = AX25PID_IP; /* wrong */
ax_ether2ax(ð->ether_shost, ax25.ah_src);
ax_ether2ax(ð->ether_dhost, ax25.ah_dst);
break;
}
#ifdef DEBUG2
len = 0;
for(m=m0; m; m=m->m_next) {
cp = mtod(m, u_char *);
n = m->m_len;
while(n-->0) {
if( !(len++ % 16) )
printf("\n\t");
printf("%2x ", *cp++);
}
}
if( len % 16 )
printf("\n");
#endif
break;
default:
log(LOG_INFO, "ax%d: cannot handle af%d\n", ifp->if_unit,
dst->sa_family);
m_freem(m0);
return EAFNOSUPPORT;
}
ax25.ah_cmd = AX25CMD_UI;
ax25.ah_src[6] |= 0x01; /* %%% set low bit on src */
/*
* run through the ax25_hdr and the packet buffer counting
* how much space we need for KISS encoding.
*/
len = 2; /* KISS_END, KISS_DATA */
for(i=0, cp=(u_char *)&ax25; i< sizeof(ax25); i++, cp++) {
len++;
if(*cp==KISS_END || *cp==KISS_ESC)
len++;
}
for(m=m0; m; m=m->m_next) {
cp = mtod(m, u_char *);
for(i=0; i< m->m_len; i++, cp++) {
len++;
if(*cp==KISS_END || *cp==KISS_ESC)
len++;
}
}
len++; /* KISS_END */
if( !(mp = allocb(len, BPRI_MED)) ) {
log(LOG_INFO, "ax%d: ax_output cannot allocb %d bytes\n",
ifp->if_unit, len);
m_freem(m0);
return ENOSR;
}
#ifdef DEBUG2
cp2 = mp->b_wptr;
#endif
/*
* KISS-format the ax25 header and data into mp.
*/
*mp->b_wptr++ = KISS_END;
*mp->b_wptr++ = KISS_DATA;
for(i=0, cp=(u_char *)&ax25; i<sizeof(ax25); i++, cp++) {
switch(*cp) {
case KISS_END:
*mp->b_wptr++ = KISS_ESC;
*mp->b_wptr++ = KISS_TEND;
break;
case KISS_ESC:
*mp->b_wptr++ = KISS_ESC;
*mp->b_wptr++ = KISS_TESC;
break;
default:
*mp->b_wptr++ = *cp;
break;
}
}
for(m=m0; m; m=m->m_next) {
cp = mtod(m, u_char *);
for(i=0; i< m->m_len; i++, cp++) {
switch(*cp) {
case KISS_END:
*mp->b_wptr++ = KISS_ESC;
*mp->b_wptr++ = KISS_TEND;
break;
case KISS_ESC:
*mp->b_wptr++ = KISS_ESC;
*mp->b_wptr++ = KISS_TESC;
break;
default:
*mp->b_wptr++ = *cp;
break;
}
}
}
*mp->b_wptr++ = KISS_END; /* superfluous, really */
#ifdef DEBUG2
printf("actual serial output:\n");
while(cp2 < mp->b_wptr)
printf("%2x ", *cp2++);
printf("\n");
#endif
s = splstr();
if(axp->q)
putq(axp->q, mp);
else
freemsg(mp);
(void) splx(s);
m_freem(m0);
return 0;
}
/*
* convert an ethernet ARP packet to an AX25 ARP packet. The AX25 frame
* header is not included.
*/
ax_ether2axarp(m)
struct mbuf *m;
{
struct arphdr *arp = mtod(m, struct arphdr *);
struct ether_addr eth1, eth2;
struct in_addr in1, in2;
caddr_t cp;
arp->ar_hrd = AX25_HARDTYPE;
arp->ar_pro = AX25_IPTYPE;
arp->ar_hln = 7;
cp = ((caddr_t)arp) + sizeof(struct arphdr);
bcopy(cp, (caddr_t)ð1, sizeof(struct ether_addr));
cp += sizeof(struct ether_addr);
bcopy(cp, (caddr_t)&in1, sizeof(struct in_addr));
cp += sizeof(struct in_addr);
bcopy(cp, (caddr_t)ð2, sizeof(struct ether_addr));
cp += sizeof(struct ether_addr);
bcopy(cp, (caddr_t)&in2, sizeof(struct in_addr));
cp = ((caddr_t)arp) + sizeof(struct arphdr);
ax_ether2ax(ð1, (u_char *)cp);
cp += 7;
bcopy((caddr_t)&in1, cp, sizeof(struct in_addr));
cp += sizeof(struct in_addr);
ax_ether2ax(ð2, (u_char *)cp);
cp += 7;
bcopy((caddr_t)&in2, cp, sizeof(struct in_addr));
m->m_len += 2;
return 0;
}
/*
* convert an AX25 ARP packet to an ethernet ARP packet. The AX25 frame
* is assumed to have been already stripped off.
*/
ax_ax2etherarp(m)
struct mbuf *m;
{
struct arphdr *arp = mtod(m, struct arphdr *);
u_char axa1[7], axa2[7];
struct in_addr in1, in2;
caddr_t cp;
#ifdef DEBUG2
printf("[INCOMING AX25 arp packet]");
ax25_arpdebug(m);
#endif
arp->ar_hrd = ARPHRD_ETHER;
arp->ar_pro = ETHERTYPE_IP;
arp->ar_hln = sizeof(struct ether_addr);
cp = ((caddr_t)arp) + sizeof(struct arphdr);
bcopy(cp, (caddr_t)axa1, 7);
cp += 7;
bcopy(cp, (caddr_t)&in1, sizeof(struct in_addr));
cp += sizeof(struct in_addr);
bcopy(cp, (caddr_t)axa2, 7);
cp += 7;
bcopy(cp, (caddr_t)&in2, sizeof(struct in_addr));
cp = ((caddr_t)arp) + sizeof(struct arphdr);
ax_ax2ether(axa1, (struct ether_addr *)cp);
cp += sizeof(struct ether_addr);
bcopy((caddr_t)&in1, cp, sizeof(struct in_addr));
cp += sizeof(struct in_addr);
ax_ax2ether(axa2, (struct ether_addr *)cp);
cp += sizeof(struct ether_addr);
bcopy((caddr_t)&in2, cp, sizeof(struct in_addr));
m->m_len -= 2;
return 0;
}
/*
* convert an ax25_addr to an ether_addr
*/
ax_ax2ether(axhp, ethp)
u_char *axhp;
struct ether_addr *ethp;
{
u_char c;
int i;
#ifdef DEBUG2
for(i=0; i<6; i++)
printf("%2x.", axhp[i]);
printf("%2x '", axhp[6]);
for(i=0; i<(7-1); i++)
printf("%c", (axhp[i]>>1) & 0x7f );
printf("-%c' == ", (axhp[6]&0x7f)>>1 & 0x7f );
#endif
if( !bcmp((caddr_t)axhp, (caddr_t)ax25broadcastaddr,
sizeof(ax25broadcastaddr)) ) {
bcopy((caddr_t)ðerbroadcastaddr, (caddr_t)ethp,
sizeof(struct ether_addr));
goto done;
}
ethp->ether_addr_octet[0] = 0x99;
c = ((((axhp[0]>>1) - ' ') << 2) & 0xfc);
c |= ((((axhp[1]>>1) - ' ') >> 4) & 0x03);
ethp->ether_addr_octet[1] = c;
c = ((((axhp[1]>>1) - ' ') << 4) & 0xf0);
c |= ((((axhp[2]>>1) - ' ') >> 2) & 0x0f);
ethp->ether_addr_octet[2] = c;
c = ((((axhp[2]>>1) - ' ') << 6) & 0xc0);
c |= ((((axhp[3]>>1) - ' ') ) & 0x3f);
ethp->ether_addr_octet[3] = c;
c = ((((axhp[4]>>1) - ' ') << 2) & 0xfc);
c |= ((((axhp[5]>>1) - ' ') >> 4) & 0x03);
ethp->ether_addr_octet[4] = c;
c = ((((axhp[5]>>1) - ' ') << 4) & 0xf0);
c |= (((((axhp[6]&0x7f)>>1) - '0') ) & 0x0f);
ethp->ether_addr_octet[5] = c;
done:
#ifdef DEBUG2
for(i=0; i<sizeof(struct ether_addr)-1; i++)
printf("%2x:", ethp->ether_addr_octet[i]);
printf("%2x\n", ethp->ether_addr_octet[5]);
#endif
return 0;
}
/*
* convert an ether_addr to an ax25_addr
*/
ax_ether2ax(ethp, axhp)
struct ether_addr *ethp;
u_char *axhp;
{
u_char c;
int i;
#ifdef DEBUG2
for(i=0; i<sizeof(struct ether_addr)-1; i++)
printf("%2x:", ethp->ether_addr_octet[i]);
printf("%2x == ", ethp->ether_addr_octet[5]);
#endif
if( !bcmp((caddr_t)ethp, (caddr_t)ðernulladdr,
sizeof(struct ether_addr))) {
#ifdef DEBUG2
printf("nothing\n");
#endif
for(i=0; i<7; i++)
axhp[i] = (u_char)0;
return;
}
if( !bcmp((caddr_t)ethp, (caddr_t)ðerbroadcastaddr,
sizeof(struct ether_addr))) {
bcopy((caddr_t)ax25broadcastaddr, (caddr_t)axhp,
sizeof(ax25broadcastaddr));
goto done;
}
c = ethp->ether_addr_octet[0];
if(c != 0x99) {
#ifdef DEBUG2
printf("[NO MAPPING]\n");
#endif
for(i=0; i<7; i++)
axhp[i] = (u_char)0;
return;
}
c = (ethp->ether_addr_octet[1] >> 2) & 0x3f;
axhp[0] = (u_char)((c + ' ') << 1);
c = (ethp->ether_addr_octet[1] << 4) & 0x30;
c |= (ethp->ether_addr_octet[2] >> 4) & 0x0f;
axhp[1] = (u_char)((c + ' ') << 1);
c = (ethp->ether_addr_octet[2] << 2) & 0x3c;
c |= (ethp->ether_addr_octet[3] >> 6) & 0x03;
axhp[2] = (u_char)((c + ' ') << 1);
c = (ethp->ether_addr_octet[3] ) & 0x3f;
axhp[3] = (u_char)((c + ' ') << 1);
c = (ethp->ether_addr_octet[4] >> 2) & 0x3f;
axhp[4] = (u_char)((c + ' ') << 1);
c = (ethp->ether_addr_octet[4] << 4) & 0x30;
c |= (ethp->ether_addr_octet[5] >> 4) & 0x0f;
axhp[5] = (u_char)((c + ' ') << 1);
c = (ethp->ether_addr_octet[5] ) & 0x0f;
axhp[6] = (u_char)((c + '0') << 1);
done:
#ifdef DEBUG2
for(i=0; i<6; i++)
printf("%2x.", axhp[i]);
printf("%2x '", axhp[6]);
for(i=0; i<6; i++)
printf("%c", (axhp[i] >> 1) & 0x7f );
printf("-%c'\n", ((axhp[6] & 0x7f) >> 1) & 0x7f );
#endif
return;
}
print_ax25addr(axhp)
u_char *axhp;
{
int i;
#ifdef DEBUG2
for(i=0; i<6; i++)
printf("%2x.", axhp[i]);
printf("%2x", axhp[6]);
#endif
printf("(");
for(i=0; i<6; i++)
printf("%c", (axhp[i]>>1) & 0x7f );
printf("-%c)", ((axhp[6]&0x7f)>>1) & 0x7f );
}
ax25_arpdebug(m0)
struct mbuf *m0;
{
struct mbuf *m;
int len, n;
u_char *cp;
len = 0;
for(m=m0; m; m=m->m_next) {
printf("*");
cp = mtod(m, u_char *);
n = m->m_len;
while(n-->0) {
if( !(len++ % 16) )
printf("\n\t");
printf("%2x ", *cp++);
}
}
if( len % 16 )
printf("\n");
}
#endif /* !(NAX > 0) */